package site.xuqing.socketbus.core;

import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import site.xuqing.nobean.obj.INonObject;
import site.xuqing.socketbus.core.handler.ServerEventHandler;
import site.xuqing.socketbus.core.queue.EventQueue;
import site.xuqing.socketbus.listener.OnSocketServerClientListener;

/**
 * @author xuqing
 * @Description SocketServer类，用于管理服务
 * @createTime 2022年01月21日 09:58:57
 */
public class SocketServer extends Thread {
    private volatile boolean open = true;
    private ServerSocket server;
    private final EventQueue mQueue=new EventQueue();
    private int port;
    private final OnSocketServerClientListener mOnSocketServerClientListener;
    private final Map<Integer, Socket> mSocketMap = new HashMap<>();
    private final Map<String, Integer> mRoutePortMap = new HashMap<>();
    
    
    public SocketServer(int port, OnSocketServerClientListener onSocketServerClientListener) {
        this.port = port;
        this.mOnSocketServerClientListener = onSocketServerClientListener;
    }
    
    public void setServerPort(int port) {
        this.port = port;
    }
    
    public int getServerPort() {
        return port;
    }
    
    public void close() {
        try {
            this.open = false;
            server.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    private void open() {
        try {
            server = new ServerSocket();
            // 是否复用未完全关闭的地址端口
            server.setReuseAddress(true);
            // 等效Socket#setReceiveBufferSize
            server.setReceiveBufferSize(64 * 1024 * 1024);
            // 设置serverSocket#accept超时时间
            // server.setSoTimeout(2000);
            // 设置性能参数：短链接，延迟，带宽的相对重要性
            server.setPerformancePreferences(1, 1, 1);
            // 绑定到本地端口上
            server.bind(new InetSocketAddress(Inet4Address.getLocalHost(), port), 50);
            System.out.println("服务器start～");
            System.out.println("服务器信息：" + server.getInetAddress() + " P:" + server.getLocalPort());
            
            if (mOnSocketServerClientListener != null) {
                mOnSocketServerClientListener.onSuccess();
            }
            
            while (open) {
                Socket clientSocket = server.accept();
                System.out.println("客户端连接：" + server.getInetAddress() + " P:" + clientSocket.getPort());
                setSocket(clientSocket.getPort(), clientSocket);
                ServerEventHandler serverEventHandler = new ServerEventHandler(clientSocket, this);
                serverEventHandler.start();
            }
        } catch (IOException e) {
            e.printStackTrace();
            try {
                server.close();
            } catch (IOException ioException) {
                ioException.printStackTrace();
                server = null;
            }
            if (mOnSocketServerClientListener != null) {
                mOnSocketServerClientListener.onError();
            }
        }
    }
    
    public void setSocket(int port, Socket socket) {
        mSocketMap.put(port, socket);
    }
    
    public Socket getSocket(int port) {
        return mSocketMap.get(port);
    }
    
    public void removeSocket(int port) {
        mSocketMap.remove(port);
    }
    
    /**
     * 获取指定route的SocketClient
     *
     * @param route route
     * @return SocketClient
     */
    public Integer getRoutePort(String route) {
        return mRoutePortMap.get(route);
    }
    
    public void setRoutePort(String route, int port) {
        mRoutePortMap.put(route, port);
    }
    
    public void removeRoutePort(String route) {
        mRoutePortMap.remove(route);
    }
    
    public List<INonObject> outQueue(String route) {
        return mQueue.outQueue(route);
    }
    
    public void inQueue(String route,INonObject msg) {
        mQueue.inQueue(route, msg);
    }
    
    @Override
    public void run() {
        open();
    }
}
